//
//  Disk.cpp
//  RayTracer
//
//  Created by 俞云康 on 3/25/16.
//  Copyright © 2016 yushroom. All rights reserved.
//

#include "Disk.hpp"

Disk::Disk(const string& name,
           const float radius,
           const std::shared_ptr<Transform>& transform)
    :   Shape(name, transform),
        radius(radius),
        radius_squared(radius*radius)
{
    position = transform->point2world(float3(0, 0, 0));
    normal = transform->normal2world(Normal(0, 0, 1));
    normal.normalize_self();
    D = -Dot(position, normal);
}

bool Disk::intersect(const Ray& r, HitInfo* hit) const {
    // intersect with the plane
    float n_dot_d = Dot(normal, r.dir);
    float t;
    if (n_dot_d != 0) {
        t = -(D + Dot(normal, r.o)) / n_dot_d;
        if (t <= EPS || t >= r.maxt)
            return false;
    }
    float3 p = r.at(t);
    if (DistanceSquared(p, position) > radius_squared)
        return false;
    r.maxt = t;
    hit->position = p;
    hit->normal = normal;
    return true;
}

bool Disk::intersect(const Ray& r) const {
    // intersect with the plane
    float n_dot_d = Dot(normal, r.dir);
    float t;
    if (n_dot_d != 0) {
        t = -(D + Dot(normal, r.o)) / n_dot_d;
        if (t <= EPS || t >= r.maxt)
            return false;
    }
    float3 p = r.at(t);
    if (DistanceSquared(p, position) > radius_squared)
        return false;
    return true;
}

float Disk::area() const {
    return M_PI * radius_squared;
}

Position Disk::sample(const Sample& sample, Normal* shape_normal) const {
    Position p;
    ConcentricSampleDisk(sample, &p.x, &p.y);
    // p in local space
    p.x *= radius;
    p.y *= radius;
    p.z = 0;
    p = transform->point2world(p);
    *shape_normal = normal;
    return p;
}